#include <QDateTime>
#include <QDebug>
#include "cttgipsconnector.h"
#include "cpackagecrc.h"
#include "ttgipsprotocol.h"
#include "cnetwork.h"
#include "knx/cmei.h"
#include "serversetting.h"

static unsigned char g_msg_header[11] = {0xAA,0x55,0x0,0x0};   // magic code + 2byte length
static char ips_password[16] = {0},ips_username[16] = {0};

static _u8 common_data_buffer[MAX_RECV_MSG_LEN] = {0};
static _u8 common_buffer_ttg[MAX_RECV_MSG_LEN];

static _u8 g_common_buff_ttg[MAX_RECV_MSG_LEN] = {0};
static _u8 g_common_read_buff[MAX_RECV_MSG_LEN] = {0},g_common_read_buff_ttg[MAX_RECV_MSG_LEN] = {0};
static _u8 g_common_analyze_buff_ttg[255] = {0};
static _u8 g_connect_state_buff[MAX_RECV_MSG_LEN] = {0};

static unsigned char secondEncryBuffer[MAX_RECV_MSG_LEN]= {0};
static unsigned char secondDecryBuffer[MAX_RECV_MSG_LEN]= {0};

static unsigned char entable[] = {
    136, 187,  117 , 111 , 131 , 144 , 188 , 54 , 204 , 37, //10
    102 , 73 , 11 , 1  ,165 , 100 , 190  ,149 , 91 , 27 , //20
    249 , 179 , 184 , 252 , 246 , 71 , 224 , 225 , 69 , 77,//30
    106 , 15 , 214  ,240 , 98 , 132 , 128 , 61 , 55 , 12, //40
    220 , 49 , 44 , 153 , 94 , 138 , 56 , 139 , 185 , 16,  //50
    70 , 39 , 191 , 221 , 235,  81,  196 , 123 , 101 , 119,//60
    241 , 168 , 90 , 72 , 216 , 134 , 57 , 30 , 174 , 0 , //70
    195 , 28 , 147 , 229 , 143 , 50 , 170 , 112 , 199,  2,  //80
    86 , 254 , 114 , 141 , 180 , 228 , 40 , 74 , 62 , 193 ,//90
    205,  95 , 151 , 75 , 155 , 208 , 36 , 76 , 183 , 85 , //100
    8 , 59 , 5 , 175 , 223 , 93 , 13 , 122 , 137 , 247,  //110
    201 , 242 , 211 , 26 , 89 , 53 , 126 , 145 , 125 , 92, //120
    51 , 167 , 42 , 64 , 116 , 105 , 173 , 7 , 34 , 97 , //130
    157 , 46 , 96 , 233 , 200 , 161 , 23 , 129 , 253 , 133 ,//140
    232 , 255,  103 , 230 , 78 , 67 , 218 , 163 , 19 , 140  ,//150
    109 , 33 , 194 , 226 , 80 , 231 , 213 , 6 , 79 , 48,  //160
    162 , 243 , 238 , 87 , 222 , 172 , 14 , 38 , 186 , 212 , //170
    154 , 63 , 22 , 52,  245 , 164 , 160 , 31 , 4 , 198 , //180
    239 , 219 , 248 , 43 , 88 , 227 , 32 , 197 , 24 , 234 , //190
    108 , 192 , 113 , 210 , 120 , 177 , 83 , 207 , 118 , 20 , //200
    25 , 104 , 215 , 159 , 124 , 130 , 244 , 115 , 60 , 68 , //210
    181 , 121 , 135 , 127 , 217 , 182 , 206 , 176 , 45 , 110 ,//220
    158 , 171 , 150 , 166 , 65 , 152 , 17 , 203 , 84 , 178  ,//230
    189 , 146 , 3 , 237 , 99  ,107 , 47 , 29 , 21 , 251 , //240
    209 , 156 , 148 , 9,  10, 18 , 35 , 66 , 236 , 82 , //250
    41 , 142 , 202 , 169 , 250 , 58 //256
};

const unsigned char enTable2[] ={
    220 , 211 , 135 , 222 , 33 , 10 , 179 , 45 , 238 , 75 , //10
    103 , 225 , 28 , 101,  204 , 72 , 125 , 63 , 16 , 36 , //20
    248 , 73 , 26 , 11 , 129 , 207 , 84 , 91 , 147 , 230 , //30
    164 , 177 , 21 , 192 , 212 ,152 , 44 , 159 , 233 , 189, //40
    234 , 110 , 209 , 119 , 23 , 244 , 58 , 141 , 83 , 190 ,//50
    245 , 167 , 120 , 19 , 178 , 187 , 151 , 219 , 149 , 243,  //60
    255 , 172 , 56 , 86 ,  183 , 17 ,  27,  246 , 171 ,  7 , //70
    226 , 98 ,  8 ,  9  , 132 ,  4 ,  29 , 59 ,  20 , 46 , //80
    32 , 1 , 156 , 112 , 176 , 52 , 130 , 239 , 2 , 71 , //90
    54 , 49 , 65 , 107 , 14 , 155 , 87 , 22 , 140 , 42 , //100
    165 , 24 , 116 , 170 , 229 , 198 , 108 , 12 , 139 , 131 , //110
    127 , 251 , 25 , 182 , 61 , 94 , 194 , 37 , 55 , 48 , //120
    69 , 74 , 99 , 34 , 254 , 213 , 117 , 62 , 163 , 161 , //130
    123 , 157 , 3 , 51 , 223 , 180 , 104 , 153 , 118 , 113,  //140
    47 , 96 , 193 , 142 , 236 , 41 , 106 , 102 , 88 , 228 , //150
    232 , 166 , 121 , 216 , 35 , 185 , 224 , 85 , 196 , 253 ,//160
    186 , 162 , 200 , 15 , 143 , 215 , 13 , 146 , 206 , 221 , //170
    68 , 60 , 199 , 168 , 235,  90 , 158  ,175 , 138 , 227 , //180
    148 , 154 , 105,  181,  128,  237,  202 , 82,  97 , 39 , //190
    30 , 160 , 231 , 70 , 76 , 5 , 81 , 242 , 0 , 89 , //200
    50 , 250 , 214 , 43 , 252 , 197 , 205 , 137 , 144 , 40 , //210
    64 , 115 , 79 , 210 , 92 , 124 , 66 , 240 , 188 , 174 , //220
    217 , 169 , 150,  136 , 247,  18 , 145 , 38,  208 , 203 , //230
    57 , 184 , 67 , 77 , 78 , 114 , 126 , 31 , 241 , 218, //240
    109 , 134 , 133 , 93 , 249 , 195 , 191 , 173 , 95 , 201 , //250
    100 , 80 , 53 , 6 , 122 , 111                       // 256
};


#define KNX_RECV "/tmp/recv_fifo"
#define KNX_SEND "/tmp/send_fifo"

CTTGIpsConnector::CTTGIpsConnector(QObject *parent) :
    QObject(parent)
{
    udp = NULL;
    _gateWayState = CMD_IPAD_P2P_HAND_FAIL;
    _hearThread.run_state = false;

    if(ServerSetting::defaultSetting()->_network == "0")
        usingSocket = false;
    else
        usingSocket = true;

    connect(&_hearThread,SIGNAL(s_sendHeartBreak()),this,SLOT(heartBreak()));
    connect(&_hearThread,SIGNAL(s_heartBreakState(int)),this,SLOT(heartBreakCheck(int)));

    _readCheckTimer.setInterval(500);
    _writeCheckTimer.setInterval(500);

    connect(&_readCheckTimer,SIGNAL(timeout()),this,SLOT(doReadCheck()));
    connect(&_writeCheckTimer,SIGNAL(timeout()),this,SLOT(doWriteCheck()));
}

void CTTGIpsConnector::setNetWork(QString ip,int port)
{
    if(usingSocket)
    {
        if(udp)
        {
            udp->close();
            disconnect(udp, 0, 0, 0);
        }
        else
        {
            udp = new QUdpSocket();
        }

        if(!udp->bind(QHostAddress("0.0.0.0"),port))
        {
            qDebug() << QString("TTG ips: bind port fail: %1").arg(port);
        }
        else
        {
            connect(udp,SIGNAL(readyRead()),this,SLOT(readDataSocket()));
        }

        serverAddr = QHostAddress(ip);
        serverPort = port;
    }
    else
    {
        _knxSendChannel.setFileName(KNX_SEND);
        if(!_knxSendChannel.open(QFile::WriteOnly))
            qDebug() << "open channel fail:" << KNX_SEND;

        _knxRcvChannel.setFileName(KNX_RECV);
        if(_knxRcvChannel.open(QFile::ReadOnly))
        {
            connect(&_knxRcvChannel,SIGNAL(readyRead()),this,SLOT(readDataSocket()));
        }
        else
            qDebug() << "open channel fail:" << KNX_RECV;
    }
}

void CTTGIpsConnector::startConnect()
{
    _hearThread.start();
}

void CTTGIpsConnector::disConnect()
{
    qDebug() << "CTTGIpsConnector been called disconnect";
    ttg_disconnect();
    _hearThread.run_state = false;
}

bool CTTGIpsConnector::runningState()
{
    if(!_hearThread.run_state)
        qDebug() << "hearThread not running !";

    return _hearThread.run_state;
}

void CTTGIpsConnector::heartBreak()
{
    QWriteLocker locker(&lock);

    memset(g_connect_state_buff,0,MAX_DATA_BYTES_LEN);

    int size = ttg_connect_state(g_connect_state_buff);
    ttg_send_msg((char *)g_connect_state_buff,size);
}

void CTTGIpsConnector::heartBreakCheck(int state)
{
    _gateWayState = state;

    if(_gateWayState == CMD_IPAD_P2P_HAND_SUCCESS)
       emit s_gateWayConnectState(E_NO_ERROR);
    else
       emit s_gateWayConnectState(-1);
}

void CTTGIpsConnector::ttg_heart_beat_recv_msg(_int32 status_code)
{
    qDebug() << "ttg_heart_beat_recv_msg : " << (status_code == CMD_IPAD_P2P_HAND_SUCCESS ? "success":"fail") ;
    _hearThread._heartbeatState = status_code;
}

void CTTGIpsConnector::readDataSocket()
{
    QByteArray cmdBytes;
    QHostAddress peerAddr;
    unsigned short port;

    if(usingSocket)
    {
        if (udp->hasPendingDatagrams())
        {
            cmdBytes.resize(udp->pendingDatagramSize());
            udp->readDatagram(cmdBytes.data(),cmdBytes.size(),&peerAddr,&port);

            if(cmdBytes.at(0)== (char)0xAA && cmdBytes.at(1)== (char)0x55)
            {
                int len = TTGIpsProtocol::second_round_decry((_u8 *)cmdBytes.data(),cmdBytes.size(),secondDecryBuffer);
                cmdBytes = QByteArray((char *)secondDecryBuffer,len);

                data_analyze(cmdBytes,peerAddr.toString(),port);
            }
        }
    }
    else
    {
        if (_knxRcvChannel.bytesAvailable()>0)
        {
            cmdBytes = _knxRcvChannel.readAll();

            data_analyze(cmdBytes,peerAddr.toString(),port);
        }
    }



}

// 2 magic , 2 len , 7 pasw, 2 cmd,
_int32 CTTGIpsConnector::ttg_data_analyze(_u8 msg[],_u8 msg_len)
{
    _u16 cmd = (msg[11] << 8) | msg[12];

    switch (cmd) {

        case CMD_TTG_CEMI_DATA:
            return ttg_cmei_data_analyze(msg,msg_len);
        case CMD_IPAD_P2P_HAND_SUCCESS:
        case CMD_IPAD_P2P_HAND_FAIL:
            ttg_heart_beat_recv_msg(cmd);
            break;
        default:
            return FAIL;
    }

    return SUCCESS;
}

void CTTGIpsConnector::data_analyze(QByteArray bytes,QString peerIP,unsigned short peerPort)
{
    ttg_data_analyze((_u8 *)bytes.data(),bytes.length());
}

_int32 CTTGIpsConnector::ttg_cmei_data_analyze(_u8 msg[],_u8 msg_len)
{
    //AA 55 00 15 31 31 31 31 31 31 D4 CC 99 20 80 01 E0 08 0A 01 01 BD BD BB ED

    if(!ttg_data_crc_verify(msg,(int)msg_len))
    {
        qDebug() << "ttg_data_crc_verify: CRC fail !";
        return FAIL;
    }

    msg_len -= 2;  // 2 bytes crc

    _u8 *dest_addr = NULL;
    _u8 *data = NULL;
    char str_group_addr[16] = {0};
    QByteArray strAddr;
    int cemi_index = 13 ;
    short cemi_size = (short)((msg[2]<<8)|msg[3]);
    // 7 psw, 2 cmd, 2 crc
    cemi_size -= 11;

    _u8 *device_data = &msg[cemi_index];

    ttg_data_unpackage(device_data,cemi_size,g_common_analyze_buff_ttg);
    device_data = g_common_analyze_buff_ttg;

    dest_addr = &g_common_analyze_buff_ttg[3];
    cmei_get_string_group_address(str_group_addr,dest_addr);
    strAddr = QByteArray((char *)dest_addr,2);

    qDebug() << "TTG_routing_INDICATION: dest addrss " << QString(str_group_addr);

    QList<DEVICE_OBJECT *> regist_list = _registersMap.values(strAddr);
    //print_data(str_group_addr,device_data,16);
    if(regist_list.size()>0)
    {
        _u8 *device_value = NULL,value_len = 0;
        DEVICE_OBJECT *obj = NULL;
        _u8 operation_type = 0;

        //bc 2 srouce , 2 dest,
        device_value = &device_data[5];

        for (int i = 0; i < regist_list.size(); ++i) {
            obj = (DEVICE_OBJECT *)regist_list.at(i);

            _u8 *ret_value = NULL;

            routing_indication_recv_analyze(device_value,obj->_data_type,&operation_type,
                                            &ret_value,&value_len);

            _int32 source_addr_empty = FALSE;
            if (device_data[1] == 0 && device_data[2] == 0) {
                source_addr_empty = TRUE;
            }

            if(operation_type == APCI_VALUE_RESP ||
               (operation_type == APCI_VALUE_WRITE && source_addr_empty == FALSE))
            {
                message_device_data_handle(obj,ret_value,value_len);
            }
        }

    }

    return SUCCESS;
}


void CTTGIpsConnector::setLogInfo(QString username,QString password)
{
    ttg_set_pass(username.toLocal8Bit().data(),password.toLocal8Bit().data());
}

void CTTGIpsConnector::ttg_set_pass(char *user,char *pass)
{
    memset(ips_username,0,16);
    memcpy(ips_username,user,8);

    memset(ips_password,0,16);
    memcpy(ips_password,pass,6);
}

unsigned int CTTGIpsConnector::set_msg_header(char *buff)
{
    //4 bytes
    memset(buff,0,11);
    memcpy(buff,g_msg_header,4);

    // 7 bytes
    generate_encry_password(ips_password,buff+4);

    return 11;
}

void CTTGIpsConnector::generate_encry_password(char *pass,char encry_pass[7])
{
    _u32 r = 0;

    uint seed = QDateTime::currentDateTime().toTime_t();
    qsrand(seed);

    r = qrand()&0xff;

    //r = 69;

    for(int i=0;i<6;i++)
    {
        encry_pass[i] = pass[5-i];
        encry_pass[i] = encry_pass[i] ^ entable[r];
    }

    encry_pass[6] = r;
}


void CTTGIpsConnector::encry_knx_data(unsigned char random,char *knx, unsigned int size,char *encry_buf)
{
    unsigned char r = random;

    for(unsigned int i=0;i<size;i++)
    {
        encry_buf[i] = knx[size - 1 - i];
        encry_buf[i] = encry_buf[i] ^ entable[r];
    }

    encry_buf[size] = r;
}

void CTTGIpsConnector::set_package_length(char *buff_head,short length)
{
    // not include aa 55 , self
    length -= 4;

    buff_head[2] = BYTE_HI(length);
    buff_head[3] = BYTE_LOW(length);
}


_u8 CTTGIpsConnector::calc_crc_from_control1_BC(_u8 *buff,_u8 size)
{
    int i =0;
    _u8 crc = 0;
    for (i=0; i<size-1; i++) {
        if (i==0) {
            crc = buff[i] ^ buff[i+1];
        }
        else
            crc = crc ^ buff[i+1];
    }

    crc = crc ^ 0xff;

    return crc;
}

_u8 CTTGIpsConnector::package_cmei_msg_ttg(_u8 msg[],_u8 controlField1,_u8 addr[2],_u8 *value,_u8 size)
{
    // cEMI frame ----------------------------------------------

    //    int controlField1 = 0xba;      //not repeat, low
    //    int controlField2 = 0xd0;      //group address

    msg[0] = controlField1;

    //0xff 0xfe ipad default , all 0 is boardcast address
    msg[1] = 0xff;     // source address hi byte  (to be filled by gateway)
    msg[2] = 0xfe;     // source address lo byte  (to be filled by gateway)

    msg[3] = addr[0];     // dest address hi byte
    msg[4] = addr[1];     // dest address lo byte

    msg[5] = 0xE0|(size&0xf);
    msg[6] = 0x00;

    memcpy(&msg[7], value, size);

    return 7+size;
}

void CTTGIpsConnector::removeReadCheck(QByteArray addr)
{
    char tmp[16] = {0};
    cmei_get_string_group_address(tmp,(_u8 *)addr.data());
    qDebug() << "removeReadCheck:" << tmp ;

    _readList.removeOne(addr);
}

void CTTGIpsConnector::removeWriteCheck(QByteArray addr)
{
    for(int i=0;i<_writeList.size();i++)
    {
        if(_writeList.at(i).addr2bytes == addr)
        {
            _writeList.removeAt(i);
            break;
        }
    }
}

void CTTGIpsConnector::doReadCheck()
{
    static QByteArray lastAddr;

    if(_readList.size()>0)
    {
        QByteArray addr;
        // 2nd
        if(lastAddr.isEmpty())
        {
            addr = _readList.first();
            lastAddr = addr;
        }
        else // third
        {
            addr = lastAddr;

            if(addr == _readList.first())
                _readList.removeFirst();

            lastAddr.clear();
        }

        ttg_read_status((_u8 *)addr.data());

        char tmp[16] = {0};
        cmei_get_string_group_address(tmp,(_u8 *)addr.data());
        qDebug() << "doReadCheck: read again " << tmp ;
    }
    else
        _readCheckTimer.stop();

    qDebug() << "doReadCheck: size " << _readList.size() ;
}

void CTTGIpsConnector::doWriteCheck()
{
    static CIpsWriteStruct lastAddr;

    if(_writeList.size()>0)
    {
        CIpsWriteStruct s;
        // 2nd
        if(lastAddr.addr2bytes.isEmpty())
        {
            s = _writeList.first();
            lastAddr = s;
        }
        else // third
        {
            s = lastAddr;
            lastAddr.addr2bytes.clear();
            _writeList.removeFirst();
        }

        ttg_write_device((_u8 *)s.addr2bytes.data(),s.data_type,(_u8 *)s.data.data(),
                         s.data.size());
    }
    else
        _writeCheckTimer.stop();

    qDebug() << "doWriteCheck: size " << _writeList.size() ;
}

void CTTGIpsConnector::doReadDevice(QByteArray addr2bytes)
{
    ttg_read_status((_u8 *)addr2bytes.data());

//    _readList.append(addr2bytes);

//    if(!_readCheckTimer.isActive())
//        _readCheckTimer.start();
}

void CTTGIpsConnector::doWriteDevice(QByteArray addr2bytes, int data_type, QByteArray data)
{
    qDebug() << "KNX Write:" << addr2bytes.toHex();
    ttg_write_device((_u8 *)addr2bytes.data(),data_type,(_u8 *)data.data(),data.size());
//    _writeList.append(s);
//    if(!_writeCheckTimer.isActive())
//        _writeCheckTimer.start();

}

void CTTGIpsConnector::doRegistObject(void *dev, void *userdata)
{
    if(!registeObject(dev,userdata))
        qDebug() << "CTTGIpsConnector:doRegistObject fail!";
}

_int32 CTTGIpsConnector::ttg_write_device(_u8 addr[2],_u8 value_type,_u8 *data,_u32 len)
{
    QWriteLocker locker(&lock);

    _int32 msg_len = 0;

    memset(common_data_buffer, 0, MAX_DATA_BYTES_LEN);
    memset(common_buffer_ttg, 0, MAX_DATA_BYTES_LEN);

    common_data_buffer[0] = APCI_VALUE_WRITE;

    if (value_type == ONE_BIT_VALUE) {
        common_data_buffer[0] |= (*data & 0x1);
        msg_len = ttg_data_package(addr,common_data_buffer,1,common_buffer_ttg);
    }
    else
    {
        memcpy(&common_data_buffer[1], data, len);
        msg_len = ttg_data_package(addr,common_data_buffer,len+1,common_buffer_ttg);
    }

    ttg_send_msg((char *)common_buffer_ttg,msg_len);

    return 0;
}

_int32 CTTGIpsConnector::ttg_read_status(_u8 addr[])
{
    QWriteLocker locker(&lock);

    char readAddr[16] = {0};
    cmei_get_string_group_address(readAddr,addr);
    qDebug() << "read address " << readAddr;

    memset(g_common_read_buff,0,MAX_DATA_BYTES_LEN);
    memset(g_common_read_buff_ttg,0,MAX_DATA_BYTES_LEN);

    common_data_buffer[0] = APCI_VALUE_READ;
    _u8 msg_len = ttg_data_package(addr,g_common_read_buff,1,g_common_read_buff_ttg);

    ttg_send_msg((char *)g_common_read_buff_ttg,msg_len);

    return 0;
}

unsigned short CTTGIpsConnector::ttg_data_package(_u8 addr[2], _u8 *value, char value_len, _u8 *buff)
{
    _u8 *control_addr = 0;
    _u8 random = 0;

    short size = 0;
    size = set_msg_header((char *)buff);

    random = buff[size-1];          // random number is the last one

    buff[size] = 0xcc;
    buff[size+1] = 0x99;

    size += 2;          //2 cmd code

    control_addr = (_u8 *)&buff[size];

    memcpy(control_addr, ips_username, 8);
    size += 8;
    _u8 *cemi_data = control_addr + 8;

    //include 8 username， no need to encry username, just append the cmd code
    int ttg_size = package_cmei_msg_ttg(g_common_buff_ttg,0xBC,addr,value,value_len);
    g_common_buff_ttg[ttg_size] = calc_crc_from_control1_BC(g_common_buff_ttg,ttg_size);
    ttg_size += 1;

    encry_knx_data(random,(char *)g_common_buff_ttg,ttg_size,(char *)cemi_data);
    size += ttg_size + 1;  // last one is rand number

    set_package_length((char *)buff,size+2);
    short crc = CPackageCRC::crc_cal_by_byte(&buff[2],size-2); // 2 maigc head, 2 crc  not include

    buff[size] = BYTE_HI(crc);
    buff[size+1] = BYTE_LOW(crc);

    size += 2;           // 2 crc size

    return size;
}

_int32 CTTGIpsConnector::ttg_connect_state(_u8 *buff)
{
    _u8 *control_addr = 0;
    _u8 random = 0;

    short size = 0;
    size = set_msg_header((char *)buff);

    random = buff[size-1];          // random number is the last one

    buff[size] = 0x8A;
    buff[size+1] = 0x07;

    size += 2;          //2 cmd code

    control_addr = (_u8 *)&buff[size];
    memcpy(control_addr, ips_username, 8);

    size += 8 ;  // last one is rand number

    set_package_length((char *)buff,size+2);
    short crc = CPackageCRC::crc_cal_by_byte(&buff[2],size-2); // 2 maigc head, 2 crc  not include

    buff[size] = BYTE_HI(crc);
    buff[size+1] = BYTE_LOW(crc);

    size += 2;           // 2 crc size

    return size;
}

int CTTGIpsConnector::ttg_send_msg(char *buff,int size)
{
    int r = 0;
    if(usingSocket)
    {
        if(CNetwork::secondEncry)
        {
            size = TTGIpsProtocol::second_round_encry((_u8 *)buff,size,secondEncryBuffer);
            buff = (char *)secondEncryBuffer;
        }

        r = udp->writeDatagram(buff,size,serverAddr,serverPort);
    }
    else
        r = _knxSendChannel.write(buff,size);

    QThread::msleep(30);

    return r;
}

_int32 CTTGIpsConnector::ttg_disconnect()
{
    QWriteLocker locker(&lock);

    _u8 *control_addr = 0;
    _u8 random = 0;
    _u8 buff[64] = {0};

    short size = 0;
    size = set_msg_header((char *)buff);

    random = buff[size-1];          // random number is the last one

    buff[size] = 0x8A;
    buff[size+1] = 0x09;

    size += 2;          //2 cmd code

    control_addr = (_u8 *)&buff[size];
    memcpy(control_addr, ips_username, 8);

    size += 8 ;  // last one is rand number

    set_package_length((char *)buff,size+2);
    short crc = CPackageCRC::crc_cal_by_byte(&buff[2],size-2); // 2 maigc head, 2 crc  not include

    buff[size] = BYTE_HI(crc);
    buff[size+1] = BYTE_LOW(crc);

    size += 2;           // 2 crc size

    return ttg_send_msg((char *)buff, size);
}

void CTTGIpsConnector::ttg_data_unpackage(_u8 *cemi_data,int size,_u8 *decode_buf)
{
    memset(decode_buf, 0, size);

    int index = cemi_data[size-1]&0xff;
    int r = entable[index];

    int cemi_size = size-1;
    for(unsigned int i=0;i<cemi_size;i++)
    {
        decode_buf[i] = cemi_data[cemi_size - 1 - i];
        decode_buf[i] = decode_buf[i] ^ r;
    }

}

bool CTTGIpsConnector::ttg_data_crc_verify(_u8 *data,int size)
{
    // AA 55 , 2 CRC not include
    short crc = CPackageCRC::crc_cal_by_byte(data+2,size-4);

    if(data[size-2] == BYTE_HI(crc) &&
       data[size-1] == BYTE_LOW(crc)
       )
    {
        return true;
    }

    return false;
}


// Eib  Section
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool CTTGIpsConnector::registeObject(void *devObj, void *userdata)
{
    DEVICE_OBJECT *obj = (DEVICE_OBJECT *)devObj;

    //KDEBUG << QString("registeObject: dest addrss") << obj->_address.data() << obj->_data_type;

    obj->_user_data = userdata;

    _registersMap.insertMulti(QByteArray((char *)obj->_ga_ia,2) ,obj);

    return true;
}

//根据地址和控件来取消
bool CTTGIpsConnector::unRegisterObject(void *devObj,void *userdata)
{
    DEVICE_OBJECT * objs = (DEVICE_OBJECT *)devObj;

    QMultiMap<QByteArray, DEVICE_OBJECT *>::iterator i = _registersMap.begin();
    while (i != _registersMap.end()) {
        QMultiMap<QByteArray, DEVICE_OBJECT *>::iterator prev = i;
        ++i;
        if (prev.key() == QByteArray((char *)objs->_ga_ia,2))
        {
            DEVICE_OBJECT *o = prev.value();
            //服务器端,控件是不存在的,可能为 NULL
            if(o && o == objs)
            {
                _registersMap.erase(prev);
                return true;
            }
            else
                continue;
        }
    }

    return false;
}

void CTTGIpsConnector::unRegisterAll()
{
    _registersMap.clear();
}


_int32 CTTGIpsConnector::message_device_data_handle(DEVICE_OBJECT *data,_u8 *value,_u8 value_len)
{
    if (data!=NULL && value!=NULL) {
        QByteArray valueByte;

        switch (data->_data_type) {
            case ONE_BIT_VALUE:
            {
                valueByte = QByteArray((char *)value,1);
                //KDEBUG << "onebit_callback:" << data->_address << " = " << valueByte.toUInt();
                //emit engineValueNotify(data->_address,ONE_BIT_VALUE,valueByte,data->_user_data);

                break;
            }

            case ONE_BYTE_VALUE:
            case TWO_BYTES_VALUE:
            case THREE_BYTES_VALUE:
            case FOUR_BYTES_VALUE:
            {
                //skip APCI/APEI
                value ++;
                value_len --;

                valueByte = QByteArray((char *)value,value_len);
                KDEBUG << "bytes_callback:" <<  data->_address << "len = " << value_len;
                //emit engineValueNotify(data->_address,data->_data_type,QByteArray((char *)value,value_len),data->_user_data);

                break;

            }

            default:
            {
                KDEBUG << "recv_msg_handle: error data type " << data->_data_type;
                return -1;

            }

        }

        qDebug() << "value call back: " << data->_address << "size :" << valueByte.size() ;

        removeReadCheck(QByteArray((const char *)data->_ga_ia,2));
        //removeWriteCheck(QByteArray((const char *)data->_ga_ia,2));

        emit s_valueNotify((void *)data,valueByte,data->_user_data);
    }

    return 0;
}

_int32 CTTGIpsConnector::routing_indication_recv_analyze(_u8 data[],_u32 data_type,_u8 *operation_type,
                                       _u8 **ret_value,_u8 *ret_len)
{
    _u8 len = data[0];     // data len
    //_u8 tpci = data[1];      // TPCI/APCI
    _u8 *value = &data[2];
    *ret_value = value;
    *ret_len = len;

    if ( (*value&APCI_VALUE_RESP) == APCI_VALUE_RESP) {
        *operation_type = APCI_VALUE_RESP;
    }
    else if ((*value&APCI_VALUE_WRITE) == APCI_VALUE_WRITE)
    {
        *operation_type = APCI_VALUE_WRITE;
    }
    else
    {
        *operation_type = APCI_VALUE_READ;
    }

    return SUCCESS;
}



/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

CIpsHeartBreakThread::CIpsHeartBreakThread(QThread *parent) :
    QThread(parent)
{

}

// 异步线程更新_heartbeatState
int CIpsHeartBreakThread::is_connect_lost()
{
    _int32 try_time = 0 ;
    _heartbeatState = CMD_IPAD_P2P_HAND_FAIL;

    do
    {
        emit s_sendHeartBreak();
        sleep(2);
    }while(try_time++ < 2 && _heartbeatState == CMD_IPAD_P2P_HAND_FAIL);

    return _heartbeatState;
}

void CIpsHeartBreakThread::run()
{
    qDebug() << "TTG Heart beat thread start.";
    run_state = true;

    while (run_state) {

        //在判断连接保活状态
        int code = is_connect_lost();
        emit s_heartBreakState(code);

        if(code != CMD_IPAD_P2P_HAND_SUCCESS)
            sleep(5);
        else
        {
            sleep(HEART_BEAT_INTERVAL);
        }
    }

    qDebug() << "TTG Heart beat thread end.";
}

